
#pragma once

typedef enum QlObjType
{
    QL_OBJ_UNDEFINED    = 0,
    QL_OBJ_NIL          = 1,
    QL_OBJ_T            = 2,
    QL_OBJ_ID           = 3,
    QL_OBJ_CDR          = 4,
    QL_OBJ_INT          = 5,
    QL_OBJ_DOUBLE       = 6,
    QL_OBJ_STRING       = 7,
    
    QL_MAX_STD_OBJECTS_COUNT,
} QlObjType;

/*
 * virtual methods table
 */

struct QlStream;
struct QlObj;

struct QlObjVtbl
{
    QlObjType type_id;

    const char * type_name;

    struct QlObj * (* get_ref_object)(struct QlObj * obj, size_t index);

    void (* dispose)(struct QlObj * obj);

    void (* write_as_string)(struct QlObj * obj, struct QlStream * stream);
};

#define QL_OBJ_HEADER(type_name) \
    const struct QlObjVtbl * vtbl; \
    int gc_mark : 1

#define ql_type(objPtr)                 ((objPtr)->vtbl->type_id)

#define ql_type_name(objPtr)            ((objPtr)->vtbl->type_desc->type_name)

#define ql_get_ref_object(objPtr, i)    (objPtr)->vtbl->get_ref_object((struct QlObj *)objPtr, i)

#define ql_dispose(objPtr)              (objPtr)->vtbl->dispose((struct QlObj *)objPtr)

#define ql_write_as_string(objPtr, s)   (objPtr)->vtbl->write_as_string((struct QlObj *)objPtr, s)

struct QlObj
{
    QL_OBJ_HEADER(QlObj);
};

struct QlInt
{
    QL_OBJ_HEADER(QlObj);

    int value;
};

struct QlDouble
{
    QL_OBJ_HEADER(QlObj);

    double value;
};

struct QlString
{
    QL_OBJ_HEADER(QlObj);

    char str[1];
};

struct QlId
{
    QL_OBJ_HEADER(QlId);

    /*
     * unique number, associated with the string representation of
     * this identifier, with exception of namespace
     */
    size_t          token;

    /*
     * object, associated with this id
     */
    struct QlObj *  assoc_obj;
};

struct QlCdr
{
    QL_OBJ_HEADER(QlObj);

    struct QlObj * car;
    struct QlCdr * cdr;
};

